package alf.mapping.data;

import alf.common.data.AbstractDataService;
import alf.common.data.DataException;
import alf.mapping.dto.maps.Item;
import alf.mapping.dto.maps.Link;
import alf.mapping.dto.maps.MapModel;
import alf.mapping.dto.maps.Room;
import alf.mapping.view.Env;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;

//<?xml version="1.0" ?>
//<map mod="default">
//<room name="room1" mod="office" terrain="default">
//<item name="mesa1" x="500" y="500" height="64" width="64" type="mesa" link="room2">Esta mesa es muy importante</item>
//<item name="silla" x="500" y="532" height="64" width="64" type="silla" />
//</room>
//<room name="room2" mod="office" terrain="default">
//<item name="otra mesa" x="500" y="500" height="64" width="64" type="mesa">Esta mesa tampoco es importante</item>
//<item name="silla2" x="500" y="532" height="64" width="64" type="silla" />
//</room>
//</map>

public class SimpleSaver extends AbstractDataService {
	private static final String XML_HEADER = "<?xml version=\"1.0\" ?>\n";

	public void save(MapModel m, String path) throws DataException {
		try {
			if (checkExistence(path)) {
				BufferedWriter w = new BufferedWriter(new FileWriter(path));
				push(m, w);
				w.close();	
			} else {
				encapsula("error creating file " + path, null);
			}
		} catch (FileNotFoundException e) {
			encapsula("file not found " + path, e);
		} catch (IOException e) {
			encapsula("file writing error.", e);
		}
	}

	private boolean checkExistence(String path) throws IOException {
		File f = new File(path);
		if (!f.exists()) {
			return f.createNewFile();
		} else {
			return true;
		}
	}

	private void push(MapModel m, BufferedWriter w) throws IOException {
		StringBuffer attrBuffer= new StringBuffer();
		w.write(XML_HEADER);
		//	pushAttr("mod",m.getMod());
		openTag("map", attrBuffer, w, false);
		for (Room r : m.getRooms()) {
			push(r, w);
		}
		closeTag("map", w);
	}

	private void push(Room r, BufferedWriter w) throws IOException {
		StringBuffer attrBuffer = new StringBuffer();
		Env.debug("SimpleSaver.pushRoom." + r.getName());
		pushAttr(attrBuffer, "name", r.getName());
		pushAttr(attrBuffer, "mod", r.getMod());
		pushAttr(attrBuffer, "terrain", r.getTerrain());
		openTag("room", attrBuffer, w, false);
		for (Item i: r.getEntidades()) {
			push(i, w);
		}
		closeTag("room", w);
	}

	private void push(Item i, BufferedWriter w) throws IOException {
		//<item name="mesa1" x="500" y="500" height="64" width="64" type="mesa" link="room2">Esta mesa es muy importante</item>
		StringBuffer attrBuffer = new StringBuffer();

		pushAttr(attrBuffer, "name", i.getName());
		pushAttr(attrBuffer, "type", i.getType());
		pushAttr(attrBuffer, "x", i.getRect().left);
		pushAttr(attrBuffer, "y", i.getRect().top);
		pushAttr(attrBuffer, "height", i.getRect().height());
		pushAttr(attrBuffer, "width", i.getRect().width());

		String text = i.getText();
		if (text == null  && i.getLinks() == null) {
			openTag("item", attrBuffer, w, true);
		} else {
			openTag("item", attrBuffer, w, false);
			if (i.getText() != null) {
				pushText("text", i.getText(), w);
			}
			if (i.getLinks() != null) {
				for (Link link: i.getLinks()) {
					push(link, w);
				}
			}
			closeTag("item", w);
		}
	}

	private void push(Link link, BufferedWriter w) throws IOException {
		StringBuffer attrBuffer = new StringBuffer();

		pushAttr(attrBuffer, "title", link.getTitle());
		if (link.getDestination() != null) {
			pushAttr(attrBuffer, "dest", link.getDestination().toString());
		}

		pushAttr(attrBuffer, "navigable", link.isNavigable());
		pushAttr(attrBuffer, "visible", link.isVisible());

		pushAttr(attrBuffer, "style", link.getStyle());
		pushAttr(attrBuffer, "orientation", link.getOrientation());
		openTag("link", attrBuffer, w, true);

	}

	private void pushText(String tagName, String text, BufferedWriter w) throws IOException {
		openTag(tagName, null, w, false);
		if (text != null) {
			w.write(text);
		}
		closeTag(tagName, w);
	}

	private void pushAttr(StringBuffer b, String name, boolean val) {
		pushAttr(b, name, String.valueOf(val));
	}

	private void pushAttr(StringBuffer b, String name, int val) {
		pushAttr(b, name, String.valueOf(val));
	}

	private void pushAttr(StringBuffer b, String name, String value) {
		if (b != null && value != null) {
			b.append(name).append("=\"").append(value).append("\" ");
		}
	}

	private void openTag(String tagName, StringBuffer attrBuf, BufferedWriter w, boolean close) throws IOException {
		w.write("<");
		w.write(tagName);
		String attrs = null;
		if (attrBuf != null) {
			attrs = attrBuf.toString();
			if (!attrs.equals("")) {
				w.write(" ");
				w.write(attrs);
			}
		}
		if (close) {
			w.write("/>\n");
		} else {
			w.write(">\n");
		}
	}	

	private void closeTag(String tagname, BufferedWriter w) throws IOException {
		w.write("</");
		w.write(tagname);
		w.write(">\n");
	}

}
